package com.lanchetech.user.service.impl;


import com.alibaba.excel.util.CollectionUtils;
import com.baidu.fsg.uid.UidGenerator;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lanchetech.bean.request.*;
import com.lanchetech.bean.response.*;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.*;
import com.lanchetech.common.constants.BaseConstant;
import com.lanchetech.common.constants.JypConstant;
import com.lanchetech.common.enums.ResultCode;
import com.lanchetech.common.enums.SceneEnum;
import com.lanchetech.common.enums.ToggleEnum;
import com.lanchetech.common.util.SensitiveInfoUtil;
import com.lanchetech.dao.AppointmentMapper;
import com.lanchetech.dao.AppointmentSettingMapper;
import com.lanchetech.dao.ShopMapper;
import com.lanchetech.dao.UserRoleMapper;
import com.lanchetech.entity.Appointment;
import com.lanchetech.entity.AppointmentSetting;
import com.lanchetech.entity.Shop;
import com.lanchetech.entity.User;
import com.lanchetech.common.enums.*;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.CardConsumptionFundService;
import com.lanchetech.service.DaoService;
import com.lanchetech.user.config.ReturnPayInfoVO;
import com.lanchetech.user.service.CommonService;
import com.lanchetech.user.service.ShopService;
import org.hashids.Hashids;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class ShopServiceImpl implements ShopService {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    ShopMapper shopMapper;

    @Autowired
    AppointmentSettingMapper appointmentSettingMapper;

    @Autowired
    AppointmentMapper appointmentMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    UserRoleMapper userRoleMapper;

    @Autowired
    CoinFlowMapper coinFlowMapper;

    @Autowired
    UserMapper userMapper;

    @Resource
    UidGenerator uidGenerator;

    @Autowired
    CommonService commonService;

    @Autowired
    ActivityRegisterMapper activityRegisterMapper;


    @Value("${domain.url}")
    private String domainUrl;

    @Value("${appointment.hashid.salt}")
    private String salt;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    FlashSaleActivityMapper flashSaleActivityMapper;

    @Autowired
    FlashSaleSpuMapper flashSaleSpuMapper;

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    BargainActivityMapper bargainActivityMapper;

    @Autowired
    BargainSpuMapper bargainSpuMapper;

    @Autowired
    OrderCommentMapper orderCommentMapper;

    @Autowired
    OrdersMapper ordersMapper;

    @Autowired
    OrderSkuMapper orderSkuMapper;

    @Autowired
    IndustryMapper industryMapper;

    @Autowired
    ShopCollectionMapper shopCollectionMapper;

    @Autowired
    ShopRelationshipMapper shopRelationshipMapper;

    @Autowired
    MsgUserMapper msgUserMapper;

    @Autowired
    MsgMapper msgMapper;

    @Autowired
    UserVoucherMapper userVoucherMapper;

    @Autowired
    OrderPayMapper orderPayMapper;

    @Autowired
    ShopStatisticsMapper shopStatisticsMapper;

    @Autowired
    BossMapper bossMapper;

    @Autowired
    ShopAnnouncementMapper shopAnnouncementMapper;

    @Autowired
    AnnouncementMapper announcementMapper;

    @Autowired
    BossInviteShopMapper bossInviteShopMapper;

    @Autowired
    BossIdentityMapper bossIdentityMapper;

    @Autowired
    UserCommissionMapper userCommissionMapper;

    @Value("${wx.pay.appId}")
    private String miniAppId;

    @Value("${wx.app.appId}")
    private String appAppId;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private FlashSaleSkuMapper flashSaleSkuMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private CardConsumptionFundService cardConsumptionFundService;


    @Override
    public ResultData<BasePageResp<Shop>> getNearbyShopPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Shop> list = shopMapper.findAllNearbyPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<ShopDetailVO> getShopDetail(User user, Long id) {

        //更新商店统计数据
        shopStatisticsMapper.updateVisitCountByShopId(id);

        ShopDetailVO vo = new ShopDetailVO();

        vo.setShop(shopMapper.selectByPrimaryKey(id));

        // 获取当前正在进行，或者即将进行的秒杀场次
        // 获取当前进行中，或者今日最近的限时优惠
        // 先获取当前进行中的活动
        FlashSaleActivity flashSaleActivity =
                flashSaleActivityMapper.findOneStarting();
        FlashSaleSpu flashSaleSpu = null;
        if (flashSaleActivity != null) {
            flashSaleSpu = flashSaleSpuMapper.findOneByActivityIdAndShopIdAndStatusOrderBySortsDesc(flashSaleActivity.getId(), id, ToggleEnum.ON.getStatus());
        }

        if (flashSaleSpu == null) {
            flashSaleActivity = flashSaleActivityMapper.findOneLatest();
            if (flashSaleActivity != null) {
                flashSaleSpu = flashSaleSpuMapper.findOneByActivityIdAndShopIdAndStatusOrderBySortsDesc(flashSaleActivity.getId(), id, ToggleEnum.ON.getStatus());
            }
        }

        if (flashSaleSpu != null) {
            vo.setFlashSaleActivity(flashSaleActivity);
            vo.setFlashSaleSpu(flashSaleSpu);
            vo.setFlashSpu(spuMapper.selectByPrimaryKey(flashSaleSpu.getSpuId()));
        }

        // 获取正在进行的3个砍价
        List<BargainActivity> bargainActivityList = bargainActivityMapper.findThreeByShopIdAndStatus(id, ToggleEnum.ON.getStatus(), new Date());
        if (!bargainActivityList.isEmpty()) {
            List<BargainSpu> bargainSpuList = bargainSpuMapper.findAllByActivityIds(bargainActivityList.stream().map(BargainActivity::getId).collect(Collectors.toList()));
            List<BargainSpuVO> bargainSpuVOList = new ArrayList<>();
            Map<Long, Spu> spuMap = daoService.getSpuMap(bargainSpuList.stream().map(BargainSpu::getSpuId).collect(Collectors.toList()));
            bargainSpuList.stream().forEach(item -> {
                BargainSpuVO bargainSpuVO = new BargainSpuVO();
                BeanUtils.copyProperties(item, bargainSpuVO);
                bargainSpuVO.setMainImage(spuMap.get(item.getSpuId()).getMainImage());
                bargainSpuVOList.add(bargainSpuVO);
            });

            vo.setBargainActivityList(bargainActivityList);
            vo.setBargainSpuList(bargainSpuVOList);
        }

        // 体验商品
        Spu spu = spuMapper.findOneByShopIdAndTypeAndHiddenOrderBySortsDesc(id, SpuTypeEnum.SHOP.getType(), HiddenEnum.VISIBLE.getStatus());
        vo.setExperienceSpu(spu);

        List<OrderCommentResp> commentList = orderCommentMapper.findShopLatestTwo(id);
        if (!commentList.isEmpty()) {
            Map<Long, User> userMap = daoService.getUserMap(commentList.stream().map(OrderComment::getUserId).collect(Collectors.toList()));
            commentList.stream().forEach((item) -> {
                item.setAvatar(item.getAnonymous().equals((byte) 0) ? userMap.get(item.getUserId()).getAvatar() : JypConstant.ANONYMOUS_AVATAR);
                item.setNickname(item.getAnonymous().equals((byte) 0) ? userMap.get(item.getUserId()).getNickname() : SensitiveInfoUtil.chineseName(userMap.get(item.getUserId()).getNickname()));
            });
        }
        vo.setCommentList(commentList);
        vo.setCommentCount(orderCommentMapper.countByShopIdAndStatus(id, OrderCommentStatusEnum.NORMAL.getStatus()));
        vo.setOrderCount(orderSkuMapper.countByShopIdAndOrderType(id, OrderTypeEnum.ONLINE_SELF.getType()));

        // 商家在他的一级类目中的排名
        Long rank = shopMapper.countByIndustryFirstIdAndOverallStar(vo.getShop().getIndustryFirstId(), vo.getShop().getOverallStar());
        vo.setRank(rank == null ? 1L : rank + 1);

        //当前商店是否被收藏
        vo.setUserCollectionType(ToggleEnum.OFF.getStatus());
        if (user != null) {
            ShopCollection selectShopCollection = shopCollectionMapper.findOneByShopIdAndUserId(id, user.getId());
            if (selectShopCollection != null) {
                vo.setUserCollectionType(ToggleEnum.ON.getStatus());
            }
        }
        return new ResultData<>(vo);
    }

    @Override
    public ResultData<Shop> getShop(Long id) {
        return new ResultData<>(shopMapper.selectByPrimaryKey(id));
    }

    @Override
    public BaseResp editAppointmentSetting(AppointmentSetting req) {

//        if (AppointmentSettingTypeEnum.COIN.getType().equals(req.getType())) {
//            BaseResp baseResp = new BaseResp(ResultCode.FAIL);
//            baseResp.setMessage("您不能能添加或者修改积分类型的预约设置");
//            return baseResp;
//        }
        // 判断是否是该店的店长和店员
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (!req.getShopId().equals(getUserShopId(user))) {
            return new BaseResp(ResultCode.SHOP_NOT_YOU);
        }
        AppointmentSetting old = appointmentSettingMapper.findOneBySpuIdAndShopId(req.getSpuId(), getUserShopId(user));
        if (old == null) {
            req.setUserId(user.getId());
            req.setCreatedAt(new Date());
            req.setUpdatedAt(new Date());
            req.setDeleted(DeletedEnum.DEFAULT.getStatus());
            appointmentSettingMapper.insert(req);
        } else {
            req.setUpdatedAt(new Date());
            appointmentSettingMapper.updateByPrimaryKeySelective(req);
        }
        return new BaseResp();
    }

    private Long getUserShopId(User user) {
        return user.getShopId();
    }

    @Override
    public ResultData<BasePageResp<AppointmentVO>> getAppointmentPage(PageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        if (SceneEnum.OWNER.getType().equals(req.getScene())) {
            List<UserRole> userRoles = userRoleMapper.findAllByUserId(user.getId());
            userRoles.stream().forEach(item -> {
                if (UserRoleEnum.ROLE_SHOP.getId().equals(item.getRoleId()) || UserRoleEnum.ROLE_CLERK.getId().equals(item.getRoleId())) {
                    req.setShopId(item.getRelateId());
                }
            });

            if (req.getShopId() == null) {
                ResultData<BasePageResp<AppointmentVO>> resultData = new ResultData<>();
                resultData.setResultCode(ResultCode.SHOP_NOT_YOU);
                return resultData;
            }

        } else if (SceneEnum.CUSTOMER.getType().equals(req.getScene())) {
            req.setUserId(user.getId());
        } else {
            ResultData<BasePageResp<AppointmentVO>> resultData = new ResultData<>();
            resultData.setResultCode(ResultCode.FAIL);
            resultData.setMessage("未传入场景scene参数或者场景scene参数错误");
            return resultData;
        }


        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());

        List<AppointmentVO> list = appointmentMapper.findAllPage(req);
        if (!list.isEmpty()) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(AppointmentVO::getShopId).collect(Collectors.toList()));
            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(AppointmentVO::getUserId).collect(Collectors.toList()));
            Map<Long, AppointmentSetting> appointmentSettingMap = daoService.getAppointmentSettingMap(list.stream().map(AppointmentVO::getAppointmentSettingId).collect(Collectors.toList()));

            list.stream().forEach(item -> {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setMainImage(shopMap.get(item.getShopId()).getMainImage());
                item.setShopAddress(shopMap.get(item.getShopId()).getAddress());

                item.setUserNickname(userMap.get(item.getUserId()).getNickname());
                item.setUserAvatar(userMap.get(item.getUserId()).getAvatar());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }


    @Override
    public ResultData<AppointmentByDayVO> getAppointmentByDay(Date date, Long appointmentSettingId) {
        try {

            AppointmentSetting appointmentSetting = appointmentSettingMapper.selectByPrimaryKey(appointmentSettingId);
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"), sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            PageReq req = PageReq.builder()
                    .pageSize(10000)
                    .activityId(appointmentSettingId)
                    .startTime(sdf2.parse(sdf1.format(date) + " 00:00:00"))
                    .endTime(sdf2.parse(sdf1.format(date) + " 23:59:59"))
                    .commonStatus(ToggleEnum.ON.getStatus())
                    .build();
            List<AppointmentVO> list = appointmentMapper.findAllPage(req);

            return new ResultData<>(AppointmentByDayVO.builder()
                    .appointmentSetting(appointmentSetting)
                    .list(list)
                    .build());

        } catch (Exception e) {
            return null;
        }

    }

    @Override
    public ResultData<ReturnPayInfoVO> editAppointment(User user, Appointment req, HttpServletRequest httpServletRequest) {
        ResultData<ReturnPayInfoVO> resultData = new ResultData<>();
//        req.setUserId(user.getId());
//
//        AppointmentSetting appointmentSetting = appointmentSettingMapper.selectByPrimaryKey(req.getAppointmentSettingId());
//        if (appointmentSetting == null) {
//            resultData.setResultCode(ResultCode.FAIL);
//            return resultData;
//        }
//
//        Long num = appointmentMapper.countByTime(req.getTime(), req.getAppointmentSettingId());
//        if (num != null) {
//            if (num.compareTo(appointmentSetting.getNumber()) >= 0) {
//                resultData.setResultCode(ResultCode.APPOINTMENT_MORE_LIMIT);
//                return resultData;
//            }
//        }
//
//        req.setShopId(appointmentSetting.getShopId());
//        req.setEliminateStatus(ToggleEnum.OFF.getStatus());
//        req.setTradeNo(Long.toString(uidGenerator.getUID()));
//        req.setAmount(appointmentSetting.getAmount());
//        req.setStatus(AppointmentPayStatusEnum.NOT_PAY.getStatus());
//        req.setCreatedAt(new Date());
//
//        // 支付
//        ReturnPayInfoVO infoVO = null;
//        if (AppointmentPayTypeEnum.COIN.getType().equals(req.getPayType()) && AppointmentPayTypeEnum.COIN.getType().equals(appointmentSetting.getType())) {
//            // 扣除积分
//            if (user.getCoin().compareTo(appointmentSetting.getAmount()) >= 0) {
//                userMapper.updateCoinById(user.getCoin().subtract(appointmentSetting.getAmount()), user.getId());
//            } else {
//                resultData.setResultCode(ResultCode.INSUFFICIENT_BALANCE);
//                return resultData;
//            }
//
//            // 创建积分使用记录
//            coinFlowMapper.insert(CoinFlow.builder()
//                    .userId(user.getId())
//                    .amount(appointmentSetting.getAmount())
//                    .tradeType(CoinFlowTradeTypeEnum.APPOINTMENT_ORDER.getTradeType())
//                    .type(CoinFlowTradeTypeEnum.APPOINTMENT_ORDER.getType())
//                    .coin(user.getCoin().subtract(appointmentSetting.getAmount()))
//                    .relateId(null)
//                    .remark(appointmentSetting.getTitle())
//                    .createdAt(new Date())
//                    .build());
//
//            completeAppointment(req.getTradeNo());
//
//        } else if (AppointmentPayTypeEnum.WECHAT.getType().equals(req.getPayType()) && AppointmentPayTypeEnum.WECHAT.getType().equals(appointmentSetting.getType())) {
//            // 微信支付
//            // 创建微信支付
//            final WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = WxPayUnifiedOrderRequest.newBuilder()
//                    .openid(user.getOpenid())
//                    .outTradeNo(req.getTradeNo())
//                    //订单金额, 单位：分
//                    .totalFee(req.getAmount().multiply(new BigDecimal(100)).intValue())
//                    .body(StringHelper.subPayBodyString(appointmentSetting.getTitle()))
//                    .spbillCreateIp(IpUtil.getIpAddr(httpServletRequest))
//                    .notifyUrl(domainUrl + "/api/shop/appointmentOrderNotify")
//                    .build();
//            infoVO = commonService.getReturnPayInfoVO(wxPayUnifiedOrderRequest);
//        } else {
//            resultData.setResultCode(ResultCode.FAIL);
//            return resultData;
//        }


        appointmentMapper.insert(req);

//        resultData.setValue(infoVO);
        return resultData;
    }

    @Override
    public String appointmentOrderNotify(String xmlData) {
        try {
            this.wxPayService.getConfig().setAppId(xmlData.indexOf(miniAppId) > -1 ? miniAppId : appAppId);
            this.wxPayService.getConfig().setTradeType(xmlData.indexOf(miniAppId) > -1 ? "JSAPI" : "APP");
            final WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
            // 检查微信支付成功的回调是否是他人伪造
            notifyResult.checkResult(wxPayService, "MD5", true);
            log.info("订单号：{}, 门店预约下单微信支付成功！", notifyResult.getOutTradeNo());
            completeAppointment(notifyResult.getOutTradeNo());
            return WxPayNotifyResponse.success("回调成功！");
        } catch (WxPayException e) {
            e.printStackTrace();
            log.error("微信支付失败！");
            return WxPayNotifyResponse.fail("回调有误!");
        }
    }

    private void completeAppointment(String tradeNo) {
        Appointment appointment = appointmentMapper.findOneByTradeNo(tradeNo);

        if (AppointmentPayStatusEnum.NOT_PAY.getStatus().equals(appointment.getStatus())) {
            appointment.setStatus(AppointmentPayStatusEnum.PAID.getStatus());
            appointmentMapper.updateByPrimaryKeySelective(appointment);
        }

    }

    @Override
    public ResultData<BasePageResp<AppointmentSettingVO>> getAppointmentSettingPage(User user, PageReq req) {
        if (SceneEnum.OWNER.getType().equals(req.getScene())) {

            List<UserRole> userRoles = userRoleMapper.findAllByUserId(user.getId());
            userRoles.stream().forEach(item -> {
                if (UserRoleEnum.ROLE_SHOP.getId().equals(item.getRoleId()) || UserRoleEnum.ROLE_CLERK.getId().equals(item.getRoleId())) {
                    req.setShopId(item.getRelateId());
                }
            });
            if (req.getShopId() == null) {
                ResultData<BasePageResp<AppointmentSettingVO>> resultData = new ResultData<>();
                resultData.setResultCode(ResultCode.SHOP_NOT_YOU);
                return resultData;
            }
        } else if (!SceneEnum.CUSTOMER.getType().equals(req.getScene())) {
            ResultData<BasePageResp<AppointmentSettingVO>> resultData = new ResultData<>();
            resultData.setResultCode(ResultCode.FAIL);
            resultData.setMessage("未传入场景scene参数或者场景scene参数错误");
            return resultData;
        }

        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<AppointmentSettingVO> list = appointmentSettingMapper.findAllPage(req);
        if (!list.isEmpty()) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(AppointmentSettingVO::getShopId).collect(Collectors.toList()));
            Map<Long, Spu> spuMap = daoService.getSpuMap(list.stream().map(AppointmentSettingVO::getSpuId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setShopMainImage(shopMap.get(item.getShopId()).getMainImage());
                item.setShopImageList(shopMap.get(item.getShopId()).getImageList());
                item.setAddress(shopMap.get(item.getShopId()).getAddress());
                item.setBusinessStart(shopMap.get(item.getShopId()).getBusinessStart());
                item.setBusinessEnd(shopMap.get(item.getShopId()).getBusinessEnd());
                item.setSpuName(spuMap.get(item.getSpuId()).getName());
                item.setShopSpuType(spuMap.get(item.getSpuId()).getShopSpuType());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp cancelAppointment(Long id) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        // 判断订单状态
        Orders orders = ordersMapper.selectByPrimaryKey(id);
        if (OrdersStatusEnum.PAID.getStatus().equals(orders.getStatus()) && user.getId().equals(orders.getUserId()) && OrderTypeEnum.ONLINE_SELF.getType().equals(orders.getOrderType())) {
            orders.setCloseReason(CloseReasonEnum.ONLY_REFUND.getReason());
            orders.setCloseTime(new Date());
            orders.setStatus(OrdersStatusEnum.CLOSE.getStatus());
            orders.setTotalRefundAmount(orders.getTotalPayAmount());
            // 生成退款订单号
            String refundNo = Long.toString(uidGenerator.getUID());
            orders.setRefundNo(refundNo);
            ordersMapper.updateByPrimaryKeySelective(orders);

            // orderSku也变更状态
            orderSkuMapper.updateStatusByOrderId(OrdersStatusEnum.CLOSE.getStatus(), orders.getId());

            // 将代付订单改成已全部退款
            if (PayTypeEnum.ANOTHER_APY.getType().equals(orders.getPayType())) {
                orderPayMapper.updateStatusAndUpdatedAtByTradeNo(OrderPayStatusEnum.FULL_REFUND.getStatus(), new Date(), orders.getTradeNo());
            }

            if (PayTypeEnum.WECHAT.getType().equals(orders.getPayType())
                    || PayTypeEnum.ANOTHER_APY.getType().equals(orders.getPayType())
                    || PayTypeEnum.APP_WECHAT.getType().equals(orders.getPayType())
            ) {

                if (orders.getTotalPayAmount().compareTo(BigDecimal.ZERO) > 0) {
                    WxPayRefundRequest request = WxPayRefundRequest.newBuilder()
                            //订单号
                            .outTradeNo(orders.getTradeNo())
                            //退款订单号
                            .outRefundNo(refundNo)
                            //原先总金额(分)
                            .totalFee(orders.getTotalPayAmount().multiply(new BigDecimal(100)).intValue())
                            //退款金额(分)
                            .refundFee(orders.getTotalPayAmount().multiply(new BigDecimal(100)).intValue())
                            //退款回调
                            .notifyUrl(domainUrl + "/admin-api/order/refundNotify")
                            .build();

                    WxPayRefundResult wxPayRefundResult;
                    try {
                        wxPayService.getConfig().setAppId(PayTypeEnum.APP_WECHAT.getType().equals(orders.getPayType()) ? appAppId : miniAppId);
                        wxPayService.getConfig().setTradeType(PayTypeEnum.APP_WECHAT.getType().equals(orders.getPayType()) ? "APP" : "JSAPI");

                        wxPayRefundResult = wxPayService.refund(request);
                        //判断退款信息是否正确
                        if ("SUCCESS".equals(wxPayRefundResult.getReturnCode()) && "SUCCESS".equals(wxPayRefundResult.getResultCode())) {
                            log.info("主动关闭订单-微信退款请求已经成功发送");
                            if (WxPayErrCodeEnum.SYSTEMERROR.getCode().equals(wxPayRefundResult.getErrCode())
                                    || WxPayErrCodeEnum.BIZERR_NEED_RETRY.getCode().equals(wxPayRefundResult.getErrCode())) {
                                log.error("主动关闭订单-微信退款请求，重新发送");
                                wxPayRefundResult = wxPayService.refund(request);
                                if ("SUCCESS".equals(wxPayRefundResult.getReturnCode()) && "SUCCESS".equals(wxPayRefundResult.getResultCode())) {
                                    log.info("主动关闭订单-微信退款请求重新发送成功");
                                } else {
                                    log.error("主动关闭订单-微信退款请求重新发送失败");
                                }
                            }
                            return new BaseResp();
                        } else {
                            log.error("主动关闭订单-微信退款请求发送失败");
                        }
                    } catch (WxPayException e) {
                        log.error("主动关闭订单-微信退款接口错误信息= {}", e);
                    }
                } else {
                    return new BaseResp();
                }

            } else if (PayTypeEnum.EXCHANGE_CARD.getType().equals(orders.getPayType())) {
                // 将兑换卡变回可用状态
                List<OrderSkuVO> orderSkuVOList = orderSkuMapper.findAllByOrderId(orders.getId());
                userVoucherMapper.updateStatusByUseOrderSkuId(VoucherStatusEnum.AVAILABLE.getStatus(), orderSkuVOList.get(0).getId());
                // 此时只能继续使用兑换卡，不可取消订单
                // 不用处理佣金之类的事情
            }
        }

        return new BaseResp();
    }

    @Override
    public String appointmentRefundNotify(String xmlData) {
        WxPayRefundNotifyResult wxPayRefundNotifyResult;
        try {
            wxPayService.getConfig().setAppId(xmlData.indexOf(miniAppId) > -1 ? miniAppId : appAppId);
            wxPayService.getConfig().setTradeType(xmlData.indexOf(miniAppId) > -1 ? "JSAPI" : "APP");

            wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(xmlData);
            // 检查微信退款成功的回调是否是他人伪造
            wxPayRefundNotifyResult.checkResult(wxPayService, "MD5", true);
        } catch (WxPayException e) {
            log.error("主动关闭订单-退款失败，失败信息:{}", e);
            return WxPayNotifyResponse.fail("退款失败");
        }

        //判断返回状态信息是否正确，是否真的退款了
        if ("SUCCESS".equals(wxPayRefundNotifyResult.getReturnCode())) {
            WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
            //判断退款状态
            if ("SUCCESS".equals(reqInfo.getRefundStatus())) {
                String refundNo = reqInfo.getOutRefundNo();
                appointmentRefundNotifyComplete(refundNo);

                return WxPayNotifyResponse.success("退款成功！");
            }
        }
        return WxPayNotifyResponse.fail("回调有误!");
    }

    void appointmentRefundNotifyComplete(String refundNo) {
        Appointment appointment = appointmentMapper.findOneByRefundNo(refundNo);

        appointment.setStatus(AppointmentPayStatusEnum.REFUND.getStatus());
        appointmentMapper.updateByPrimaryKeySelective(appointment);
    }


    @Override
    public ResultData<AppointmentVO> getAppointmentByHashId(String hashId) {
        Hashids hashids = new Hashids(salt, 32);
        Long id = hashids.decode(hashId)[0];
        Appointment appointment = appointmentMapper.selectByPrimaryKey(id);
        AppointmentVO vo = new AppointmentVO();

        BeanUtils.copyProperties(appointment, vo);

        Shop shop = shopMapper.selectByPrimaryKey(appointment.getShopId());
        vo.setShopName(shop.getShopName());
        vo.setMainImage(shop.getMainImage());
        vo.setShopAddress(shop.getAddress());

        User user = userMapper.selectByPrimaryKey(appointment.getUserId());
        vo.setUserAvatar(user.getAvatar());
        vo.setUserNickname(user.getNickname());

        AppointmentSetting setting = appointmentSettingMapper.selectByPrimaryKey(appointment.getAppointmentSettingId());

        return new ResultData<>(vo);
    }

    @Override
    public ResultData<AppointmentVO> getAppointmentDetail(Long id) {

        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        Appointment appointment = appointmentMapper.selectByPrimaryKey(id);

        if (!appointment.getUserId().equals(user.getId())) {
            return new ResultData<>();
        }

        AppointmentVO vo = new AppointmentVO();

        BeanUtils.copyProperties(appointment, vo);

        Shop shop = shopMapper.selectByPrimaryKey(appointment.getShopId());
        vo.setShopName(shop.getShopName());
        vo.setMainImage(shop.getMainImage());
        vo.setShopAddress(shop.getAddress());

        AppointmentSetting setting = appointmentSettingMapper.selectByPrimaryKey(appointment.getAppointmentSettingId());

        Hashids hashids = new Hashids(salt, 32);
        vo.setHashId(hashids.encode(appointment.getId()));

        return new ResultData<>(vo);
    }

    @Override
    public BaseResp verifyConfirmAppointment(String hashId) {
        Hashids hashids = new Hashids(salt, 32);
        Long id = hashids.decode(hashId)[0];
        Appointment appointment = appointmentMapper.selectByPrimaryKey(id);

        // 判断商品是否处理有效状态
        if (!AppointmentPayStatusEnum.PAID.getStatus().equals(appointment.getStatus())) {
            return new BaseResp(ResultCode.FAIL);
        }

        // 先判断商品是否已经核销，
        if (AppointmentEliminateStatusEnum.NOT_VERIFY.getStatus().equals(appointment.getEliminateStatus())) {
            User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            UserRole userRole = userRoleMapper.findOneByUserIdAndRoleId(user.getId(), UserRoleEnum.ROLE_CLERK.getId());

            if (appointment.getShopId().equals(userRole.getRelateId())) {
                // 修改此商品订单状态
                appointment.setClerkId(userRole.getUserId());
                appointment.setEliminateStatus(AppointmentEliminateStatusEnum.VERIFY.getStatus());
                appointment.setEliminateTime(new Date());
                appointmentMapper.updateByPrimaryKeySelective(appointment);
            } else {
                return new BaseResp(ResultCode.NOT_THIS_SHOP_CLERK);
            }

            return new BaseResp();
        } else {
            return new BaseResp(ResultCode.ORDER_SKU_HAS_VERIFY);
        }
    }


    @Override
    public BaseResp editActivityRegister(ActivityRegister activityRegister) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (activityRegister.getId() == null) {
            //新增
            activityRegister.setUserId(user.getId());
            activityRegister.setShopId(getUserShopId(user));
            activityRegister.setCreatedAt(new Date());
            activityRegister.setUpdatedAt(new Date());
            activityRegister.setStatus(ActivityRegisterStatusEnum.PENDING.getStatus());
            activityRegisterMapper.insert(activityRegister);
        } else {
            ActivityRegister selectActivityRegister = activityRegisterMapper.selectByPrimaryKey(activityRegister.getId());
            //编辑
            //判断当前用户是否为需要修改活动报名记录的创建人 且当前用户为修改活动报名店铺的店员
            if (user.getId().equals(selectActivityRegister.getUserId()) && getUserShopId(user).equals(selectActivityRegister.getShopId())) {
                activityRegister.setUpdatedAt(new Date());
                activityRegister.setStatus(ActivityRegisterStatusEnum.PENDING.getStatus());
                activityRegisterMapper.updateByPrimaryKeySelective(activityRegister);
            } else {
                return new BaseResp(ResultCode.FAIL);
            }

        }
        return new BaseResp();
    }

    @Override
    public BaseResp deleteActivityRegister(Long id) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        ActivityRegister selectActivityRegister = activityRegisterMapper.selectByPrimaryKey(id);
        if (user.getId().equals(selectActivityRegister.getUserId()) || getUserShopId(user).equals(selectActivityRegister.getShopId())) {
            activityRegisterMapper.deleteByPrimaryKey(id);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<ActivityRegisterVO>> getActivityRegisterPage(PageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setShopId(getUserShopId(user));
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<ActivityRegisterVO> list = activityRegisterMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(ActivityRegister::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setUserNickname(userMap.get(item.getUserId()).getNickname());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<ActivityRegister> getActivityRegisterDetail(Long id) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long shopId = getUserShopId(user);
        ActivityRegister activityRegister = activityRegisterMapper.selectByPrimaryKey(id);
        if (activityRegister.getShopId().equals(shopId)) {
            return new ResultData<>(activityRegister);
        }
        return new ResultData<>();
    }

    @Override
    public ResultData<List<IndustryIdAndNameVO>> getIndustryFirstList(User user) {
        List<IndustryIdAndNameVO> list = industryMapper.selectNameAndIdByType(IndustryTypeEnum.FIRST_ID.getType());
        return new ResultData<>(list);
    }

    @Override
    public ResultData<List<IndustryIdAndNameVO>> getIndustrySecondList(PageReq req) {
        List<IndustryIdAndNameVO> list = industryMapper.selectNameAndIdBySelectivePid(req);
        return new ResultData<>(list);
    }

    private Calendar getFirstTime(Calendar calendar) {
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        return calendar;
    }

    @Override
    public ResultData<List<StatisticsVO>> getSpuAppointmentStatistics(Long spuId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, -5);
        List<StatisticsVO> list = orderSkuMapper.getSpuAppointmentStatistics(spuId, getUserShopId(user), getFirstTime(calendar).getTime());
        return new ResultData<>(list);
    }

    @Override
    public ResultData<BasePageResp<Shop>> getMyRecommendShopPage(PageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<ShopRelationship> shopRelationshipList = shopRelationshipMapper.findAllByUserId(user.getId());
        List<Long> shopIds = new ArrayList<>();
        shopRelationshipList.stream().forEach(item -> {
            shopIds.add(item.getShopId());
        });
        List<Shop> list = shopMapper.findAllByIds(shopIds);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<MsgUser> getStoreMsgUser(Long shopId, Long msgUserId) {

        // 获取商家正在服务中的客服

        // 将shopId 完全当 tenantId来使用
        List<MsgUser> list = msgUserMapper.findAllByTenantIdAndStatusAndDeleted(shopId, MsgUserStatusEnum.IN_SERVICE.getStatus(), DeletedEnum.DEFAULT.getStatus());

        if (!CollectionUtils.isEmpty(list)) {

            // 获取最近1次沟通的消息
            Msg msg = msgMapper.findOneLastByTenantIdAndFromId(shopId, msgUserId);
            // 如果沟通过，并且还在3天内
            if (msg != null && msg.getCreatedAt().getTime() + 3 * 86400 * 1000 > System.currentTimeMillis()) {
                Optional<MsgUser> msgUserOptional = list.parallelStream().filter(s -> s.getId().equals(msg.getToId())).findFirst();
                // 如果在线
                if (msgUserOptional.isPresent()) {
                    MsgUser msgUser = msgUserOptional.get();
                    msgUser.setPassword(null);
                    return new ResultData<>(msgUser);
                }
            }


            // 随机选择1个客服
            Random r = new Random();
            MsgUser msgUser = list.get(r.nextInt(list.size()));
            msgUser.setPassword(null);
            return new ResultData<>(msgUser);
        }
        return new ResultData<>(null);
    }

    @Override
    public ResultData<BasePageResp<BossVO>> getBossShopPage(PageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        req.setUserId(user.getId());
        List<BossVO> list = bossMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(BossVO::getShopId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setAvatar(shopMap.get(item.getShopId()).getAvatar());
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp switchShop(Long shopId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Boss boss = bossMapper.findOneByShopIdAndUserId(shopId, user.getId());
        if (boss != null) {
            userMapper.updateShopIdById(shopId, user.getId());
        }
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<ShopAnnouncementVO>> getShopAnnouncementPage(ShopAnnouncementPageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setShopId(user.getShopId());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<ShopAnnouncementVO> list = shopAnnouncementMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            List<Announcement> announcementList = announcementMapper.findAllByIds(list.stream().map(ShopAnnouncementVO::getAnnouncementId).collect(Collectors.toList()));
            Map<Long, Announcement> announcementMap = new HashMap<>();
            announcementList.stream().forEach(item -> {
                announcementMap.put(item.getId(), item);
            });
            list.stream().forEach(item -> {
                item.setAnnouncement(announcementMap.get(item.getAnnouncementId()));
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<ShopAnnouncementVO> getShopAnnouncementDetail(Long id) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        ShopAnnouncement shopAnnouncement = shopAnnouncementMapper.selectByPrimaryKey(id);
        ShopAnnouncementVO vo = new ShopAnnouncementVO();
        if (user.getShopId().equals(shopAnnouncement.getShopId())) {
            BeanUtils.copyProperties(shopAnnouncement, vo);
            vo.setAnnouncement(announcementMapper.selectByPrimaryKey(shopAnnouncement.getAnnouncementId()));
        }
        return new ResultData<>(vo);
    }

    @Override
    public ResultData<BasePageResp<BossInviteShopVO>> getBossInviteShopPage(BossInviteShopReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setUserId(user.getId());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BossInviteShopVO> list = bossInviteShopMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(BossInviteShopVO::getShopId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BossInviteStatisticsVO> getBossInviteStatistics(User user) {
        BossInviteStatisticsVO vo = bossInviteShopMapper.getBossInviteStatistics(user.getId());
        return new ResultData<>(vo);
    }

    @Override
    public ResultData<List<UserCommissionVO>> getBossInviteCommissionList(User user) {
        List<UserCommissionVO> list = userCommissionMapper.getBossInviteCommissionList(user.getId());
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(UserCommissionVO::getShopId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                Shop shop = shopMap.get(item.getShopId());
                if (shop != null) {
                    item.setShopName(shopMap.get(item.getShopId()).getShopName());
                    item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
                }
            });
        }
        return new ResultData<>(list);
    }

    @Override
    public ResultData<List<BossInviteShopVO>> getBossInviteShopList(User user) {
        List<BossInviteShopVO> list = bossInviteShopMapper.getBossInviteShopList(user.getId());
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(BossInviteShopVO::getShopId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setShopAvatar(shopMap.get(item.getShopId()).getAvatar());
            });
        }
        return new ResultData<>(list);
    }

    @Override
    public ResultData<BasePageResp<Shop>> getShopPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        req.setStatus(ToggleEnum.ON.getStatus());
        List<Shop> list = shopMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }


    @Override
    public ResultData<BasePageResp<SpuResp>> getSpuHomePage(SpuPageReq req, User user) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<SpuResp> respList = shopMapper.getSpuHomePage(req);
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(respList)){
            List<Long> spuIds = respList.stream().map(SpuResp::getId).distinct().collect(Collectors.toList());
            List<Sku> skuList = skuMapper.findAllBySpuIds(spuIds);
            // 是否商品有消费金抵扣
            CardConsumptionFundItemReq fundItemReq = new CardConsumptionFundItemReq();
            fundItemReq.setPageNo(BaseConstant.ONE);
            fundItemReq.setPageSize(99);
            fundItemReq.setUserId(user.getId());
            fundItemReq.setStoreId(req.getShopId());
            fundItemReq.setAccessType(AccessType.MINI);
            List<CardConsumptionFundItemVo> data = cardConsumptionFundService.getBindSpu(fundItemReq).getValue().getData();
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(data)){
                // 抵扣金额
                BigDecimal deduction = data.get(0).getDeduction();
                List<Long> cardSpus = data.stream().map(CardConsumptionFundItem::getSpuId).distinct().collect(Collectors.toList());
                respList.forEach(s->{
                    if (cardSpus.contains(s.getId())){
                        s.setDeduction(deduction);
                    }
                });
            }

            List<SkuItemVO> skuItemVOList = new ArrayList<>();
            for (Sku sku : skuList) {
                SkuItemVO itemVO = new SkuItemVO();
                BeanUtils.copyProperties(sku, itemVO);
                skuItemVOList.add(itemVO);
            }
            Map<Long, List<SkuItemVO>> skuMap = skuItemVOList.stream().collect(Collectors.groupingBy(SkuItemVO::getSpuId));
            respList.forEach(t -> t.setSkuItemVOS(skuMap.get(t.getId())));
        }
        return PageHelpUtil.buildPage(respList, page);
    }


    @Override
    public ResultData<BasePageResp<FlashSaleSpuVO>> getSpuActivityRank(SpuPageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        // 目前商家可以参与的活动有秒杀活动 和 新人专区活动
        // TODO 目前只查询秒杀活动的排行    2023-04-12
        List<FlashSaleActivity> allStartActivity = flashSaleActivityMapper.findAllStartActivity(new Date());
        List<FlashSaleSpuVO> flashSpu = new ArrayList<>();
        if (org.apache.commons.collections.CollectionUtils.isNotEmpty(allStartActivity)) {
            Map<Long, FlashSaleActivity> activityMap = allStartActivity.stream().collect(Collectors.toMap(FlashSaleActivity::getId, s -> s, (v1, v2) -> v1));
            List<Long> ids = allStartActivity.stream().map(FlashSaleActivity::getId).collect(Collectors.toList());
            flashSpu = flashSaleSpuMapper.findAllByActivityIdsAndTenantId(ids, req.getShopId());
            // 处理秒杀sku
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(flashSpu)) {
                List<FlashSaleSkuVO> flashSkus = flashSaleSkuMapper.findListByActivityIds(ids);
                if (org.apache.commons.collections.CollectionUtils.isNotEmpty(flashSkus)) {
                    Map<Long, List<FlashSaleSkuVO>> map = flashSkus.stream().collect(Collectors.groupingBy(FlashSaleSkuVO::getSpuId));
                    flashSpu.forEach(s -> {
                        s.setEndTime(activityMap.get(s.getActivityId()).getEndTime());
                        s.setActivityType(ActivityEnum.FLASH_SALE.getActivity());
                        s.setSkuVoS(map.get(s.getSpuId()));
                        int sum = s.getSkuVoS().stream().mapToInt(FlashSaleSkuVO::getActivityStock).sum();
                        s.setSpuStock(sum);
                    });
                }
            }
        }
        return PageHelpUtil.buildPage(flashSpu, page);
    }


    @Override
    public ResultData<List<Category>> getHotWords(Long shopId) {
        SpuPageReq req = new SpuPageReq();
        List<Category> allByIds = new ArrayList<>();
        req.setShopId(shopId);
        List<ShopSpuVO> spuVOS = spuMapper.findShopSpuPage(req);
        List<Long> longs = spuVOS.stream().map(ShopSpuVO::getCategoryId).distinct().collect(Collectors.toList());
        if (org.apache.commons.collections.CollectionUtils.isEmpty(longs)){
            return new ResultData<>(allByIds);
        }
        allByIds = categoryMapper.findAllByIds(longs);
        return new ResultData<>(allByIds);
    }
}